//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include <iostream>
#include <fstream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include <curl/curl.h>
//#include <curl/types.h>
#include <curl/easy.h>

#include "libraries.h"
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGHTINLINE  100000
#define DISEMBL       "http://dis.embl.de/cgiDict.py"
#define NUMBERSEQ     1
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
struct fasta {

  char  *id;
  char  *sequence;

  fasta() {
    this->id       = NULL;
    this->sequence = NULL;
  }
  
  ~fasta() {
    if (this->id)       delete[] this->id;
    if (this->sequence) delete[] this->sequence;
  }

};

#define fasta struct fasta
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace SpaceFASTA {

  bool EqualID(TNode <fasta>* NodeT, void* ref) {
    fasta*  fastaA  = NodeT->Info();
    string* fastaB  = (string*)ref;
    return (strstr(fastaA->id, fastaB->c_str()))?true:false;
  }

};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
static char   errorBuffer[CURL_ERROR_SIZE];
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void trim(char *text) {

  int i, j;
  for (i = 0, j = 0; i < strlen(text); i++)
    if ((text[i] != '\n') && (text[i] != '\r'))
      text[j++] = text[i];
  text[j] = '\0';

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void Ctrim(char *text) {

  int i, j;
  for (i = 0, j = 0; i < strlen(text); i++)
    if ((text[i] != '\n') && (text[i] != '\r') && (text[i] != ' '))
      text[j++] = text[i];
  text[j] = '\0';

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
static int writer(char *data, size_t size, size_t nmemb, string *buffer) {
  int result = 0;
  if (buffer != NULL) {
    buffer->append(data, size * nmemb);
    result = size * nmemb;
  }
  return result;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
string EraseHTMLTAG(string text) {

  do {
    size_t foundB = text.find("<");             if (foundB == string::npos) break;
    size_t foundE = text.find(">", foundB + 1); if (foundE == string::npos) break;
    text.erase(foundB, foundE - foundB + 1);
  } while (true);

  return text;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
char* SplitColumn(char* buffer, int position, const char* characters) {

  if (!buffer || !characters || (position <= 0)) return NULL;

  char *part = strtok(buffer, characters);
  if (position == 1) return part;

  int tmpPosition = 1;
  do {
    part = strtok(NULL, characters);
    tmpPosition++;
  } while (part && (tmpPosition != position));

  return part;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
string SplitFilename (const string& str) {
  size_t found;
  found = str.find_last_of("/\\");
  return str.substr(found + 1);
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int main (int argc, char** argv) {

  String* namefileIn  = NULL;
  String* namefileOut = NULL;

  if (argc < 3) {
    cout << "Error in the input parameters! Must by like: " << endl;
    cout << "./DisEMBL <input file> <output file>" << endl;
    return 0;
  }
  else {
    cout << "---------------------------------------------------------------------------------" << endl;
    cout << "  Input File : " << argv[1] << endl;
    cout << " Output File : " << argv[2] << endl;
    cout << "---------------------------------------------------------------------------------" << endl;
    namefileIn  = new String(argv[1]);
    namefileOut = new String(argv[2]);
  }

  fstream  fileIn, fileOut;
  char     buffer[LENGHTINLINE + 1], bufferA[LENGHTINLINE + 1], bufferB[LENGHTINLINE + 1];

  fileIn.open(namefileIn->Out(),   fstream::in);
  fileOut.open(namefileOut->Out(), fstream::out);

  if (!fileIn.is_open() || !fileOut.is_open()) {
    if (namefileIn)  delete namefileIn;
    if (namefileOut) delete namefileOut;
    return 0;
  }
  
  string           id                = "";
  string           sequence          = "";
  TListE <fasta>  *listData          = new TListE <fasta> ();
  
  while (!fileIn.eof()) {
    
    fasta *fastaData = new fasta ();

    fileIn.getline(bufferA, LENGHTINLINE);
    fileIn.getline(bufferB, LENGHTINLINE);

    trim(bufferA);
    Ctrim(bufferB);
    
    fastaData->id = new char[strlen(bufferA) + 1];
    strcpy(fastaData->id, bufferA);
    fastaData->id[strlen(bufferA)] = '\0';
    id = fastaData->id;

    fastaData->sequence = new char[strlen(bufferB) + 1];
    strcpy(fastaData->sequence, bufferB);
    fastaData->sequence[strlen(bufferB)] = '\0';
    sequence = fastaData->sequence;

    listData->Add(fastaData);

    struct curl_httppost* formpost = NULL;
    struct curl_httppost* lastptr  = NULL;
   
    CURL*                 curl;
    CURLcode              result;

    char                  url[LENGHTINLINE];

    string                bufferURL;
  
    curl_global_init(CURL_GLOBAL_ALL);

    curl_formadd(&formpost,
                 &lastptr,
                 CURLFORM_COPYNAME, "key",
                 CURLFORM_COPYCONTENTS, "process",
                 CURLFORM_END);

    curl_formadd(&formpost,
                 &lastptr,
                 CURLFORM_COPYNAME, "SP_entry",
                 CURLFORM_COPYCONTENTS, id.c_str(),
                 CURLFORM_END);
  
    curl_formadd(&formpost,
                 &lastptr,
                 CURLFORM_COPYNAME, "sequence_string",
                 CURLFORM_COPYCONTENTS, sequence.c_str(),
                 CURLFORM_END);
  
    curl_formadd(&formpost,
                 &lastptr,
                 CURLFORM_COPYNAME, "smooth_frame",
                 CURLFORM_COPYCONTENTS, "8",
                 CURLFORM_END);

    curl_formadd(&formpost,
                 &lastptr,
                 CURLFORM_COPYNAME, "peak_frame",
                 CURLFORM_COPYCONTENTS, "8",
                 CURLFORM_END);

    curl_formadd(&formpost,
                 &lastptr,
                 CURLFORM_COPYNAME, "join_frame",
                 CURLFORM_COPYCONTENTS, "4",
                 CURLFORM_END);

    curl_formadd(&formpost,
                 &lastptr,
                 CURLFORM_COPYNAME, "fold_coils",
                 CURLFORM_COPYCONTENTS, "1.20",
                 CURLFORM_END);

    curl_formadd(&formpost,
                 &lastptr,
                 CURLFORM_COPYNAME, "fold_rem465",
                 CURLFORM_COPYCONTENTS, "1.20",
                 CURLFORM_END);

    curl_formadd(&formpost,
                 &lastptr,
                 CURLFORM_COPYNAME, "fold_hotloops",
                 CURLFORM_COPYCONTENTS, "1.40",
                 CURLFORM_END);

    curl_formadd(&formpost,
                 &lastptr,
                 CURLFORM_COPYNAME, "doApplet",
                 CURLFORM_COPYCONTENTS, "true",
                 CURLFORM_END);

    curl_formadd(&formpost,
                 &lastptr,
                 CURLFORM_COPYNAME, "do_casp",
                 CURLFORM_COPYCONTENTS, "true",
                 CURLFORM_END);

    curl_formadd(&formpost,
                 &lastptr,
                 CURLFORM_COPYNAME, "Submit",
                 CURLFORM_COPYCONTENTS, "DisEMBL protein",
                 CURLFORM_END);

    sprintf(url, DISEMBL);
    cout    << "Retrieving " << url << endl;
    
    curl = curl_easy_init();

    if (curl) {

      curl_easy_setopt(curl, CURLOPT_ERRORBUFFER,      errorBuffer);
      curl_easy_setopt(curl, CURLOPT_URL,              url);
      curl_easy_setopt(curl, CURLOPT_HEADER,           0);
      curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,   1);
      curl_easy_setopt(curl, CURLOPT_HTTPPOST,         formpost);
      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,    writer);
      curl_easy_setopt(curl, CURLOPT_WRITEDATA,       &bufferURL);

      result = curl_easy_perform(curl);
      curl_easy_cleanup(curl);

      string        resultQuery;
      
      if (result == CURLE_OK) {
        
        size_t  foundInit, foundEnd;
        string  str;
        
        str = "<param name=\"yvalues0\" value=\""; 
        foundInit = bufferURL.find(str);
        str = "\">";                                           
        foundEnd  = bufferURL.find(str, foundInit + 1);
          
        string resultLoopsCoils = bufferURL.substr(foundInit + strlen("<param name=\"yvalues0\" value=\""), foundEnd - foundInit - strlen("<param name=\"yvalues0\" value=\""));
        
        str = "<param name=\"yvalues1\" value=\""; 
        foundInit = bufferURL.find(str, foundEnd  + 1);
        str = "\">";                                           
        foundEnd  = bufferURL.find(str, foundInit + 1);
          
        string resultHotLoops = bufferURL.substr(foundInit + strlen("<param name=\"yvalues1\" value=\""), foundEnd - foundInit - strlen("<param name=\"yvalues1\" value=\""));
        
        str = "<param name=\"yvalues2\" value=\""; 
        foundInit = bufferURL.find(str, foundEnd  + 1);
        str = "\">";                                           
        foundEnd  = bufferURL.find(str, foundInit + 1);
          
        string resultRemark465 = bufferURL.substr(foundInit + strlen("<param name=\"yvalues2\" value=\""), foundEnd - foundInit - strlen("<param name=\"yvalues2\" value=\""));
        
        str = "<h3>Disordered by Loops/coils definition</h3>"; 
        foundInit = bufferURL.find(str, foundEnd  + 1);
        str = "<br>";                                           
        foundInit = bufferURL.find(str, foundInit  + 1);
        str = "</tt>";                                           
        foundEnd  = bufferURL.find(str, foundInit + 1);
          
        string seqLoopsCoils = bufferURL.substr(foundInit + strlen("<br>"), foundEnd - foundInit - strlen("<br>"));
        
        str = "<h3>Disordered by Hot-loops definition</h3>"; 
        foundInit = bufferURL.find(str, foundEnd  + 1);
        str = "<br>";                                           
        foundInit = bufferURL.find(str, foundInit  + 1);
        str = "</tt>";                                           
        foundEnd  = bufferURL.find(str, foundInit + 1);
          
        string seqHotLoops = bufferURL.substr(foundInit + strlen("<br>"), foundEnd - foundInit - strlen("<br>"));
        
        str = "<h3>Disordered by Remark-465 definition</h3>"; 
        foundInit = bufferURL.find(str, foundEnd  + 1);
        str = "<br>";                                           
        foundInit = bufferURL.find(str, foundInit  + 1);
        str = "</tt>";                                           
        foundEnd  = bufferURL.find(str, foundInit + 1);
          
        string seqRemark465 = bufferURL.substr(foundInit + strlen("<br>"), foundEnd - foundInit - strlen("<br>"));
        
        cout         << id.c_str()                << endl;
        cout << "<"  << sequence.c_str()          << endl;
        
        fileOut         << id.c_str()                << endl;
        fileOut << "<"  << sequence.c_str()          << endl;
        
        seqLoopsCoils = EraseHTMLTAG(seqLoopsCoils);
        char tmpSeqLoopsCoils [strlen(seqLoopsCoils.c_str()) + 1];
        strcpy(tmpSeqLoopsCoils, seqLoopsCoils.c_str());
        tmpSeqLoopsCoils[strlen(seqLoopsCoils.c_str())] = '\0';
        Ctrim(tmpSeqLoopsCoils);
        seqLoopsCoils = tmpSeqLoopsCoils;
        
        cout << "+"  << seqLoopsCoils.c_str()    << endl;
        cout << "-"  << resultLoopsCoils.c_str() << endl;
        
        fileOut << "+"  << seqLoopsCoils.c_str()    << endl;
        fileOut << "-"  << resultLoopsCoils.c_str() << endl;
        
        seqHotLoops = EraseHTMLTAG(seqHotLoops);
        char tmpSeqHotLoops [strlen(seqHotLoops.c_str()) + 1];
        strcpy(tmpSeqHotLoops, seqHotLoops.c_str());
        tmpSeqHotLoops[strlen(seqHotLoops.c_str())] = '\0';
        Ctrim(tmpSeqHotLoops);
        seqHotLoops = tmpSeqHotLoops;
        
        cout << "/"  << seqHotLoops.c_str()      << endl;
        cout << "\\" << resultHotLoops.c_str()   << endl;
        
        fileOut << "/"  << seqHotLoops.c_str()      << endl;
        fileOut << "\\" << resultHotLoops.c_str()   << endl;
        
        seqRemark465 = EraseHTMLTAG(seqRemark465);
        char tmpSeqRemark465 [strlen(seqRemark465.c_str()) + 1];
        strcpy(tmpSeqRemark465, seqRemark465.c_str());
        tmpSeqRemark465[strlen(seqRemark465.c_str())] = '\0';
        Ctrim(tmpSeqRemark465);
        seqRemark465 = tmpSeqRemark465;
        
        cout << "%"  << seqRemark465.c_str()     << endl;
        cout << "&"  << resultRemark465.c_str()  << endl;
        
        fileOut << "%"  << seqRemark465.c_str()     << endl;
        fileOut << "&"  << resultRemark465.c_str()  << endl;
        
      }

    }
    
  }
  
  fileIn.close();
  fileOut.close();

  if (listData)    delete listData;
  
  if (namefileIn)  delete namefileIn;
  if (namefileOut) delete namefileOut;

  return 1;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//


